package 动态代理实现日志记录;

// 导入 Java 反射包中的关键类：
// - InvocationHandler：用于定义代理对象的方法调用逻辑
// - Method：表示类中的一个方法（反射机制）
// - Proxy：用于创建动态代理实例
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 定义一个接口 Calculator，包含两个基本的计算方法：add 和 subtract
interface Calculator {
    int add(int a, int b);
    int subtract(int a, int b);
}

// 实现类 CalculatorImpl，实现了 Calculator 接口的具体功能
class CalculatorImpl implements Calculator {
    @Override
    public int add(int a, int b) {
        return a + b;
    }

    @Override
    public int subtract(int a, int b) {
        return a - b;
    }
}

// 主程序类 LoggingProxyExample
public class LoggingProxyExample {
    public static void main(String[] args) {
        // 创建真实目标对象（被代理的对象）
        Calculator realCalculator = new CalculatorImpl();

        // 使用 Proxy.newProxyInstance() 方法创建一个动态代理对象
        // 参数解释如下：
        // 1. ClassLoader: 使用目标类的类加载器来加载生成的代理类
        // 2. Class<?>[] interfaces: 要代理的接口数组，即 Calculator.class
        // 3. InvocationHandler: 指定代理对象上所有方法调用的处理逻辑
        Calculator proxyCalculator = (Calculator) Proxy.newProxyInstance(
                Calculator.class.getClassLoader(),         // 获取接口的类加载器,jdk提供的这个Proxy要求被代理的对象必须实现一个接口
                new Class[]{Calculator.class},              // 需要代理的接口类型
                new LoggingInvocationHandler(realCalculator) // 处理方法调用的 InvocationHandler
        );

        // 调用代理对象的 add 方法
        // 这个调用会被转发到 LoggingInvocationHandler 的 invoke() 方法中
        int result = proxyCalculator.add(5, 3);
        System.out.println("Result: " + result);

        // 调用代理对象的 subtract 方法
        result = proxyCalculator.subtract(10, 4);
        System.out.println("Result: " + result);
    }
}

// 自定义的 InvocationHandler 实现类
// 当通过代理对象调用方法时，JVM 会将调用委托给这个类的 invoke() 方法
class LoggingInvocationHandler implements InvocationHandler {
    private final Object target; // 被代理的真实对象

    // 构造函数，传入被代理的目标对象
    public LoggingInvocationHandler(Object target) {
        this.target = target;
    }

    /**
     * 拦截代理对象的方法调用，并在此处添加日志记录逻辑
     *
     * @param proxy  生成的代理对象本身（一般不用）
     * @param method 被调用的方法对象（来自反射 API）
     * @param args   方法调用时传入的参数数组
     * @return       方法执行的结果
     * @throws Throwable 如果方法调用过程中抛出异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在方法调用前打印日志信息
        System.out.println("Before method " + method.getName());

        // 打印方法调用时的参数
        if (args != null) {
            System.out.print("Arguments: ");
            for (Object arg : args) {
                System.out.print(arg + " ");
            }
            System.out.println();
        }

        // 使用反射调用 Method.invoke() 来执行目标对象上的实际方法
        // 参数说明：
        // - target: 被代理的真实对象（这里是 CalculatorImpl）
        // - args: 方法参数数组
        Object result = method.invoke(target, args);

        // 方法执行后打印返回值
        System.out.println("After method " + method.getName());
        System.out.println("Return value: " + result);

        // 返回方法调用的结果
        return result;
    }
}